package com.yl.module.property.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.yl.common.config.jianke.JianKeProperties;
import com.yl.common.constant.Constants;
import com.yl.common.core.domain.entity.SysUser;
import com.yl.common.core.domain.message.MessageAlarmContent;
import com.yl.common.core.domain.message.MessageCurtainSwitch;
import com.yl.common.core.domain.message.MessageInfo;
import com.yl.common.core.domain.message.MessageLampSwitch;
import com.yl.common.domain.base.vo.Echarts2SeriesVO;
import com.yl.common.domain.base.vo.Echarts2VO;
import com.yl.common.domain.base.vo.EchartsSeriesVO;
import com.yl.common.domain.base.vo.EchartsVO;
import com.yl.common.enums.ErrorCode;
import com.yl.common.enums.YesNoEnum;
import com.yl.common.exception.ServiceException;
import com.yl.common.utils.*;
import com.yl.common.utils.date.LocalDateTimeUtils;
import com.yl.framework.interceptor.UserContext;
import com.yl.framework.web.service.WebSocketJiankeSever;
import com.yl.module.common.domain.SystemCommon;
import com.yl.module.common.service.SystemCommonService;
import com.yl.module.file.domain.FileType;
import com.yl.module.file.domain.vo.File2VO;
import com.yl.module.file.service.FileService;
import com.yl.module.property.domain.*;
import com.yl.module.property.domain.dto.*;
import com.yl.module.property.domain.vo.*;
import com.yl.module.property.mapper.PropertyBimUeInfoMapper;
import com.yl.module.property.mapper.PropertyMapper;
import com.yl.module.property.service.*;
import com.yl.system.service.ISysUserService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.ArrayStack;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import cn.hutool.core.bean.BeanUtil;

import java.io.File;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;


/**
 * 资产表 Service实现类
 * @author makejava
 * @date 2024-10-23 15:54:15
 */
@Service
@Slf4j
public class PropertyServiceImpl extends ServiceImpl<PropertyMapper, Property> implements PropertyService {

	@Autowired
	PropertyMapper propertyMapper;
	@Autowired
	PropertyTypeService propertyTypeService;
	@Autowired
	FileService fileService;
	@Autowired
	PropertyUpkeepService propertyUpkeepService;
	@Autowired
	PropertyMaintainService propertyMaintainService;

	@Resource(name = "taskExecutor")
	private ThreadPoolTaskExecutor executorService;

	@Autowired
	private PropertyRunDataService propertyRunDataService;
	@Autowired
	private ISysUserService sysUserService;
	@Autowired
	private JianKeProperties jianKeProperties;
	@Autowired
	private PropertyBimUeInfoService propertyBimUeInfoService;
	@Autowired
	private SystemCommonService systemCommonService;
	@Autowired
	private PropertyBimUeInfoMapper propertyBimUeInfoMapper;



   /**
	 * 查询所有
	 */
	@Override
	public List<PropertyVO> getAll(){
		List<Property> list = this.list();
		List<PropertyVO> result = BeanUtil.copyToList(list, PropertyVO.class);
		return result;
	}

	/**
     * 分页查询
     */
	@Override
    public Page<PropertyVO> getPage(PropertyPageDTO dto){

		Page<Property> page = dto.createPage(dto);
		LambdaQueryWrapper<Property> lqw = new LambdaQueryWrapper<>();

		lqw.eq(Property::getPropertyTypeId, dto.getPropertyTypeId());
		if(StrUtil.isNotBlank(dto.getSearchText())){
			lqw.like(true,Property::getName,dto.getSearchText())
					.or()
					.like(true,Property::getBrand,dto.getSearchText())
					.or()
					.like(Property::getPropertyCode,dto.getSearchText())
			;
		}
		if (CollUtil.isNotEmpty(dto.getPropertyTypeIds())) {
			lqw.nested(
					r->r.in(Property::getPropertyTypeId2,dto.getPropertyTypeIds())
							.or()
							.in(Property::getPropertyTypeId3,dto.getPropertyTypeIds())
			);
		}
		if(!NumberUtils.integerEmpty(dto.getState())){
			//正常
			if(dto.getState().equals(Property.PropertyStateEnum.STATE1.getCode())){
				lqw.eq(Property::getIsIdle, Constants.NO);
				lqw.eq(Property::getIsOffline, Constants.YES);
			}
			//离线
			if(dto.getState().equals(Property.PropertyStateEnum.STATE2.getCode())){
				lqw.eq(Property::getIsSmart, Constants.YES);
				lqw.eq(Property::getIsOffline, Constants.NO);
			}
			//闲置
			if(dto.getState().equals(Property.PropertyStateEnum.STATE3.getCode())){
				lqw.eq(Property::getIsIdle, Constants.YES);
			}
		}

		if (Objects.nonNull(dto.getBindBim())){
			if (!dto.getBindBim()){
				lqw.eq(Property::getUeCode,"");
			} else {
				lqw.ne(Property::getUeCode,"");
			}
		}

		lqw.eq(Property::getDeleteFlag, Constants.NO);
		this.page(page, lqw);
		if(CollectionUtils.isEmpty(page.getRecords())){
			return PageUtils.empty(page);
		}

		Page<PropertyVO> result = PageUtils.entiryTypeConvert(page, PropertyVO.class);
		List<PropertyVO> records = result.getRecords();
		Set<Integer> propertyTypeIds = new HashSet<>();
				records.stream()
				.filter(i -> i != null && !i.equals(0))
				.forEach(i -> {
					propertyTypeIds.add(i.getPropertyTypeId());
					propertyTypeIds.add(i.getPropertyTypeId2());
					propertyTypeIds.add(i.getPropertyTypeId3());
				});
		Map<Integer, PropertyType> propertyTypeMap = propertyTypeService.getMapByIds(new ArrayList<>(propertyTypeIds));

		for(PropertyVO i:records){
			i.setState(Property.PropertyStateEnum.convertState(i.getIsSmart(),i.getIsOffline(),i.getIsIdle()));
			i.setPropertyTypePathName("");

			//  处理类型全路径名称
			String propertyTypePathName = handleTypePathName(propertyTypeMap, Lists.newArrayList(i.getPropertyTypeId(),i.getPropertyTypeId2(),i.getPropertyTypeId3()));
			i.setPropertyTypePathName(propertyTypePathName);
		}
		return result;
	}

	/**
	 * 处理类型全路径名称
	 * @param list
	 */
	private String handleTypePathName(Map<Integer, PropertyType> map,List<Integer> list){
		if(MapUtil.isEmpty(map)||CollUtil.isEmpty(list)){
			return "";
		}

		list = list.stream().filter(i->!NumberUtils.integerEmpty(i)).collect(Collectors.toList());

		List<String> pathName = new ArrayList<>();
		for(Integer i:list){
			if(!map.containsKey(i)){
				continue;
			}
			pathName.add(propertyTypeService.getNameByMap(map,i));
		}

		String result = String.join("/", pathName);
		return result;
	}

	/**
	 * 通过主键查询
	 */
	@Override
	public PropertyVO getByKey(Integer id){
		Property entity = super.getById(id);
		if(Objects.isNull(entity)){
			throw new ServiceException("没有此资产");
		}
		PropertyVO result = BeanUtil.copyProperties(entity, PropertyVO.class);

		Integer state = 0;
		Property.PropertyStateEnum.convertState(result.getIsSmart(),result.getIsOffline(),result.getIsIdle());
		result.setState(state);

		ArrayList<Integer> integers = Lists.newArrayList(result.getPropertyTypeId(), result.getPropertyTypeId2(), result.getPropertyTypeId3());

		// 处理类型全路径名称
		List<Integer> propertyTypeIds = Lists.newArrayList(result.getPropertyTypeId(),result.getPropertyTypeId2(), result.getPropertyTypeId3())
				.stream()
				.filter(i->!NumberUtils.integerEmpty(i))
				.collect(Collectors.toList());
		Map<Integer, PropertyType> propertyTypeMap = propertyTypeService.getMapByIds(propertyTypeIds);
		result.setPropertyTypePathName(handleTypePathName(propertyTypeMap,propertyTypeIds));

		List<File2VO> files = fileService.get(FileType.TypeEnum.FILE_TYPE_1000.getCode(), id);
		result.setFiles(files);

        return result;
    }

	/**
	 * 添加
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer add(PropertyAddOrUpdDTO dto){
		if(StrUtil.isNotBlank(dto.getBimCode())){
			LambdaQueryWrapper<Property> lqw = new LambdaQueryWrapper<>();
			lqw.eq(Property::getBimCode,dto.getBimCode());
			List<Property> list = this.list(lqw);
			if(CollUtil.isNotEmpty(list)){
				throw new ServiceException("此BIM编码已经关联其他资产，不能被使用，请重新选择BIM编码");
			}
		}

		Property property = BeanUtil.copyProperties(dto, Property.class);

		//查看bim编码在bim基础表中是否存在
		if(StrUtil.isNotBlank(dto.getBimCode())){
			LambdaQueryWrapper<PropertyBimUeInfo> lqwBimUe = new LambdaQueryWrapper<>();
			lqwBimUe.eq(PropertyBimUeInfo::getBimCode,dto.getBimCode());
			List<PropertyBimUeInfo> bimUeInfos = propertyBimUeInfoService.list(lqwBimUe);
			if(CollUtil.isEmpty(bimUeInfos)){
				throw new ServiceException("BIM编码数据异常");
			}
			property.setUeCode(bimUeInfos.get(0).getUeCode());
		}

		property.setPropertyCode(systemCommonService.getUniqueNum(SystemCommon.UniqueNumEnum.PROPERTY_SN.getPrefix(), SystemCommon.UniqueNumEnum.PROPERTY_SN.getRedisKey()));
		this.save(property);
		//如果是构件 那么需要把分类的保养信息转给分类下面的资产
		maintainByPropertyType(dto);

		if(!CollectionUtils.isEmpty(dto.getFileCoverIds())){
			fileService.addSave(property.getId(),dto.getFileCoverIds());
		}

		return property.getId();
	}

	/**
	 * 如果是构件 那么需要把分类的保养信息通过给分类下面的资产
	 */
	public void maintainByPropertyType(PropertyAddOrUpdDTO dto){
		if(!dto.getPropertyTypeId().equals(PropertyType.IdEnum.ID_4.getCode())){
			return;
		}
		if(NumberUtils.integerEmpty(dto.getPropertyTypeId3())){
			throw new ServiceException("构件添加或修改，字段propertyTypeId3必传");
		}

		//修改资产
		//准备需要修改的数据
		Property entity = new Property();
		entity.setIsMaintain(dto.getIsMaintain());
		entity.setMaintainPeriod(dto.getMaintainPeriod());
		entity.setNextTimeMaintain(dto.getNextTimeMaintain());
		entity.setUpdateTime(LocalDateTime.now());
		//修改条件
		LambdaUpdateWrapper<Property> luw = new LambdaUpdateWrapper<>();
		luw.eq(Property::getPropertyTypeId3, dto.getPropertyTypeId3());
		//开始修改
		this.update(entity, luw);

		//修改资产分类
		//准备需要修改的数据
		PropertyType propertyTypeUpd = new PropertyType();
		propertyTypeUpd.setId(dto.getPropertyTypeId3());
		propertyTypeUpd.setIsMaintain(dto.getIsMaintain());
		propertyTypeUpd.setMaintainPeriod(dto.getMaintainPeriod());
		propertyTypeUpd.setNextTimeMaintain(dto.getNextTimeMaintain());
		propertyTypeUpd.setUpdateTime(LocalDateTime.now());
		//开始修改
		propertyTypeService.updateById(propertyTypeUpd);
	}

	/**
	 * 通过主键修改
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void upd(PropertyAddOrUpdDTO dto){
		if(StrUtil.isNotBlank(dto.getBimCode())){
			LambdaQueryWrapper<Property> lqw = new LambdaQueryWrapper<>();
			lqw.eq(Property::getBimCode,dto.getBimCode());
			lqw.ne(Property::getId,dto.getId());
			List<Property> list = this.list(lqw);
			if(CollUtil.isNotEmpty(list)){
				throw new ServiceException("此BIM编码已经关联其他资产，不能被使用，请重新选择BIM编码");
			}
		}

		Property propertyUpd = BeanUtil.copyProperties(dto, Property.class);
		propertyUpd.setUpdateTime(LocalDateTime.now());

		//闲置后 维保信息不能被修改 所以这里设置为null
		Property property = this.getById(dto.getId());
		if(Constants.YES.equals(property.getIsIdle())){
			propertyUpd.setInstallDate(null);
			propertyUpd.setIsMaintain(null);
			propertyUpd.setMaintainPeriod(null);
			propertyUpd.setNextTimeMaintain(null);
			propertyUpd.setIsChange(null);
			propertyUpd.setLatelyChangeDate(null);
		}

		if(StrUtil.isNotBlank(dto.getBimCode())){
			LambdaQueryWrapper<PropertyBimUeInfo> lqwBimUe = new LambdaQueryWrapper<>();
			lqwBimUe.eq(PropertyBimUeInfo::getBimCode,dto.getBimCode());
			List<PropertyBimUeInfo> bimUeInfos = propertyBimUeInfoService.list(lqwBimUe);
			if(CollUtil.isEmpty(bimUeInfos)){
				throw new ServiceException("数据异常");
			}
			propertyUpd.setUeCode(bimUeInfos.get(0).getUeCode());
		}

		this.updateById(propertyUpd);
		//如果是构件 那么需要把分类的保养信息通过给分类下面的资产
		maintainByPropertyType(dto);

		fileService.updSave(FileType.TypeEnum.FILE_TYPE_1000.getCode(),dto.getId(),dto.getFileCoverIds());
	}

	@Override
	public void enableIdle(PropertyEnableIdleDTO dto){
		Property propertyUpd = BeanUtil.copyProperties(dto, Property.class);
		propertyUpd.setUpdateTime(LocalDateTime.now());
		//闲置会设置点位为空
		propertyUpd.setUeCode("");
		propertyUpd.setBimCode("");
		this.updateById(propertyUpd);
	}

	@Override
	@SneakyThrows
	public PropertyStatisticsVO statistics(Integer propertyTypeId){

		PropertyStatisticsVO result = new PropertyStatisticsVO();
		CountDownLatch countDownLatch = new CountDownLatch(3);

		CompletableFuture.runAsync(() -> {
			result.setUpkeepNear30(upkeepNear30(propertyTypeId));
		}, executorService).exceptionally(e -> {
			log.error("维修统计（近30日）-数据获取失败", e);
			return null;
		}).thenRun(countDownLatch::countDown);

		CompletableFuture.runAsync(() -> {
			result.setMaintainNear30(maintainNear30(propertyTypeId));
		}).exceptionally(e -> {
			log.error("保养统计（近30日）-数据获取失败", e);
			return null;
		}).thenRun(countDownLatch::countDown);

		CompletableFuture.runAsync(() -> {
			result.setMaintainOverDue(maintainOverDue(propertyTypeId));
		}).exceptionally(e -> {
			log.error("保养超期-数据获取失败", e);
			return null;
		}).thenRun(countDownLatch::countDown);

		countDownLatch.await();

		return result;
	}

	/**
	 * 维修统计（近30日）
	 */
	public EchartsVO upkeepNear30(Integer propertyTypeId){
		LocalDateTime ldt = LocalDateTimeUtil.now();
		LocalDateTime ldt2 = ldt.plusDays(-30);
		ldt2 = LocalDateTime.of(ldt2.getYear(), ldt2.getMonthValue(),ldt2.getDayOfMonth(), 0, 0, 0);

		LambdaQueryWrapper<PropertyUpkeep> lqw = new LambdaQueryWrapper<>();
		lqw.eq(PropertyUpkeep::getPropertyTypeId,propertyTypeId);
		lqw.ge(PropertyUpkeep::getCreateTime,ldt2);
		List<PropertyUpkeep> list = propertyUpkeepService.list(lqw);

		Map<String, Long> countMap = list.stream()
				.collect(
						Collectors.groupingBy(
								i -> {
									LocalDateTime createTime = i.getCreateTime();
									int month = createTime.getMonthValue();
									int day = createTime.getDayOfMonth();
									return month + "-" + day;
								},
								Collectors.counting()
				));

		//X轴数据
		List<String> xDate = LocalDateTimeUtils.getDayByTimeNum2(ldt, 30);
		//Y轴数据
		List<BigDecimal> yDate = new ArrayList<>();
		for(String i:xDate){
			if(!countMap.containsKey(i)){
				yDate.add(BigDecimal.ZERO);
				continue;
			}
			yDate.add(new BigDecimal(countMap.get(i)));
		}

		//组装为前端需要的格式
		EchartsVO echartsVO = new EchartsVO(
				xDate,
				Lists.newArrayList(
						new EchartsSeriesVO(
								"维修量",
								EchartsSeriesVO.TypeEnum.LINE.getCode(),
								yDate)
				)
		);

		return echartsVO;
	}

	/**
	 * 保养统计（近30日）
	 */
	public EchartsVO maintainNear30(Integer propertyTypeId){
		LocalDateTime now = LocalDateTimeUtil.now();
		LocalDateTime ldt = now.plusDays(-30);
		ldt = LocalDateTime.of(ldt.getYear(), ldt.getMonthValue(),ldt.getDayOfMonth(), 0, 0, 0);

		LambdaQueryWrapper<PropertyMaintain> lqw = new LambdaQueryWrapper<>();
		lqw.eq(PropertyMaintain::getPropertyTypeId,propertyTypeId);
		lqw.ge(PropertyMaintain::getCreateTime,ldt);
		List<PropertyMaintain> list = propertyMaintainService.list(lqw);

		Map<String, Long> countMap = list.stream()
				.collect(
						Collectors.groupingBy(
								i -> {
									LocalDateTime createTime = i.getCreateTime();
									int month = createTime.getMonthValue();
									int day = createTime.getDayOfMonth();
									return month + "-" + day;
								},
								Collectors.counting()
						));

		//X轴数据
		List<String> xDate = LocalDateTimeUtils.getDayByTimeNum2(now, 30);
		//Y轴数据
		List<BigDecimal> yDate = new ArrayList<>();
		for(String i:xDate){
			if(!countMap.containsKey(i)){
				yDate.add(BigDecimal.ZERO);
				continue;
			}
			yDate.add(new BigDecimal(countMap.get(i)));
		}

		//组装为前端需要的格式
		EchartsVO echartsVO = new EchartsVO(
				xDate,
				Lists.newArrayList(
						new EchartsSeriesVO(
								"保养量",
								EchartsSeriesVO.TypeEnum.LINE.getCode(),
								yDate)
				)
		);

		return echartsVO;
	}

	/**
	 * 保养超期
	 */
	public Echarts2VO maintainOverDue(Integer propertyTypeId){
		Echarts2VO echarts2VO = new Echarts2VO(Echarts2VO.EnumType.PIE.getType());

		//查询超期数据
		LambdaQueryWrapper<Property> lqw = new LambdaQueryWrapper<>();
		lqw.eq(Property::getPropertyTypeId,propertyTypeId);
		lqw.eq(Property::getDeleteFlag,Constants.NO);
		lqw.eq(Property::getIsIdle,Constants.NO);
		//小于
		lqw.lt(Property::getNextTimeMaintain,LocalDateTime.now());
		List<Property> propertyList = this.list(lqw);

		Map<Integer, Long> countMap;
		if(propertyTypeId.equals(PropertyType.IdEnum.ID_4.getCode())){
			//构件的保养是按照三级分类来保养的 在资产数据统计中 相同的三级分类资产 只能统计一次 所以这里需要按照三级分类先去重
			propertyList = propertyList.stream()
					.collect(Collectors.toMap(
							Property::getPropertyTypeId3, // 使用 getPropertyTypeId3 作为键
							property -> property,  // 保留 Property 对象
							(existing, replacement) -> existing // 保留第一个出现的对象
					))
					.values()
					.stream()
					.collect(Collectors.toList());
		}

		countMap = propertyList.stream()
				.collect(
						Collectors.groupingBy(
								Property::getPropertyTypeId2,//按照资产分类二级进行分组统计
								Collectors.counting()
						));

		//查询分类数据
		LambdaQueryWrapper<PropertyType> lqwPropertyType = new LambdaQueryWrapper<>();
		lqwPropertyType.eq(PropertyType::getDeleteFlag,Constants.NO);
		List<PropertyType> propertyTypeList = propertyTypeService.list(lqwPropertyType);
		Map<Integer,PropertyType> propertyTypeMap = propertyTypeList.stream()
				.collect(Collectors.toMap(i -> i.getId(), Function.identity()));

		//组装为饼图
		List<Echarts2SeriesVO> data = Lists.newArrayList();
		for(Integer i:countMap.keySet()){
			Echarts2SeriesVO echarts2SeriesVO = new Echarts2SeriesVO();
			echarts2SeriesVO.setName(propertyTypeService.getNameByMap(propertyTypeMap,i));

			if(!countMap.containsKey(i)){
				echarts2SeriesVO.setValue(BigDecimal.ZERO);
			}else{
				echarts2SeriesVO.setValue(new BigDecimal(countMap.get(i)));
			}

			data.add(echarts2SeriesVO);
		}
		echarts2VO.setData(data);

		return echarts2VO;
	}

	@Override
	public PropertyInfoVO getPropertyInfo(String ueCode){
		Property property = this.getOne(new LambdaQueryWrapper<Property>().eq(Property::getUeCode,ueCode));
		if(Objects.isNull(property)){
			throw new ServiceException("未找到资产信息");
		}
		if(Objects.isNull(Constants.YES.equals(property.getIsIdle()))){
			throw new ServiceException("此资产已闲置");
		}

		PropertyInfoVO result = BeanUtil.copyProperties(property, PropertyInfoVO.class);

		//资产分类名称
		List<Integer> propertyTypeIds = Lists.newArrayList(result.getPropertyTypeId(),result.getPropertyTypeId2(), result.getPropertyTypeId3())
				.stream()
				.filter(i->!NumberUtils.integerEmpty(i))
				.collect(Collectors.toList());
		Map<Integer, PropertyType> propertyTypeMap = propertyTypeService.getMapByIds(propertyTypeIds);
		result.setPropertyTypePathName(handleTypePathName(propertyTypeMap,propertyTypeIds));

		//状态state
		LocalDateTime currentDate = LocalDateTime.now();
		result.setState(Property.PropertyUeStateEnum.convertState(result.getIsOffline(),result.getAlarmState()));
		//保养状态
		result.setMaintainState(Property.MaintainStateEnum.convertState(result.getIsMaintain(),result.getNextTimeMaintain(),currentDate));
		//更换状态
		result.setChangeState(Property.ChangeStateEnum.convertState(result.getIsChange(),result.getLatelyChangeDate(),currentDate));

		//资产运行读数
		PropertyRunData propertyRunData = propertyRunDataService.getOne(
				new LambdaQueryWrapper<PropertyRunData>()
						.eq(PropertyRunData::getPropertyUniqueCode,property.getTripartitePropertyId())
						.eq(PropertyRunData::getType,PropertyRunData.JiankeRequestTypeEnum.TYPE_3.getCode())
						.eq(PropertyRunData::getIsNew, Constants.YES)
						.eq(PropertyRunData::getDeleteFlag, Constants.NO));
		if(!Objects.isNull(propertyRunData)){
			String jsonData = propertyRunData.getJsonData();
			PropertyRunData.DeviceAttribute propertyReadData = JSONUtil.toBean(jsonData, PropertyRunData.DeviceAttribute.class);
			result.setDeviceRunData(propertyReadData);
		}

		//近30日报警数
		Long recently30AlarmNum = propertyRunDataService.count(
				new LambdaQueryWrapper<PropertyRunData>()
						.eq(PropertyRunData::getPropertyUniqueCode,property.getTripartitePropertyId())
						.eq(PropertyRunData::getType,PropertyRunData.JiankeRequestTypeEnum.TYPE_2.getCode())
						.ge(PropertyRunData::getCreateTime,currentDate.minusDays(30))
						.eq(PropertyRunData::getDeleteFlag,Constants.NO)
		);
		result.setRecently30AlarmNum(recently30AlarmNum);

		//近30日维修记录数
		Long recently30UpkeepNum = propertyUpkeepService.count(
				new LambdaQueryWrapper<PropertyUpkeep>()
						.eq(PropertyUpkeep::getPropertyId,property.getId())
						.eq(PropertyUpkeep::getDeleteFlag,YesNoEnum.NO.getCode())
						.ge(PropertyUpkeep::getCreateTime,currentDate.minusDays(30))
		);
		result.setRecently30UpkeepNum(recently30UpkeepNum);

		List<File2VO> files = fileService.get(FileType.TypeEnum.FILE_TYPE_1000.getCode(), property.getId());
		result.setFiles(files);

		return result;
	}

	@Override
	public List<PropertyUpkeepMaintainVO> getPropertyUpkeepMaintain(Integer propertyId,String ueCode){
		if(NumberUtils.integerEmpty(propertyId) && StrUtil.isBlank(ueCode)){
			throw new ServiceException("参数propertyId和ueCode不能同时为空");
		}

		Property property;
		if(!NumberUtils.integerEmpty(propertyId)){
			property = this.getById(propertyId);
		}else{
			LambdaQueryWrapper<Property> lqw = new LambdaQueryWrapper<>();
			lqw.eq(Property::getUeCode,ueCode);
			List<Property> list = this.list(lqw);
			if(list.size()>1){
				throw new ServiceException("数据异常");
			}
			property = list.get(0);
		}
		if(Objects.isNull(property)){
			throw new ServiceException("没有此资产");
		}

		Integer propertyTypeId3 = null;
		if(property.getPropertyTypeId().equals(PropertyType.IdEnum.ID_4.getCode())){
			propertyTypeId3 = property.getPropertyTypeId3();
		}

		List<PropertyUpkeepMaintainVO> list = this.propertyMapper.getPropertyUpkeepMaintain(property.getId(), propertyTypeId3);
		if(CollUtil.isEmpty(list)){
			return new ArrayList<>();
		}

		//文件
		List<Object> ids = list.stream()
				.map(i -> i.getId())
				.collect(Collectors.toList());
		List<Integer> fileTypeIds = Lists.newArrayList(
				FileType.TypeEnum.FILE_TYPE_1001.getCode(),
				FileType.TypeEnum.FILE_TYPE_1002.getCode(),
				FileType.TypeEnum.FILE_TYPE_1003.getCode()
		);
		Map<String,List<File2VO>> fileMap = fileService.getMap(fileTypeIds, ids);

		//用户
		List<Long> userIds = list.stream()
				.filter(i -> !NumberUtils.longEmpty(i.getUserId()))
				.map(i -> i.getUserId())
				.collect(Collectors.toList());
		Map<Long, SysUser> userMap = sysUserService.getMapByIds(userIds);

		//资产分类
		List<Integer> propertyTypeIds = list.stream()
				.filter(i -> !NumberUtils.integerEmpty(i.getPropertyTypeId3()))
				.map(i -> i.getPropertyTypeId3())
				.collect(Collectors.toList());
		Map<Integer,PropertyType> propertyTypeMap = propertyTypeService.getMapByIds(propertyTypeIds);

		for(PropertyUpkeepMaintainVO i:list){
			i.setPropertyName(property.getName()+" "+i.getId());

			//文件
			String fileKey = "";
			if(i.getType().equals(Property.MaintainUpkeepType.TYPE_1.getCode())){
				fileKey = FileType.TypeEnum.FILE_TYPE_1001.getCode()+"-"+i.getId();
			}else if(i.getType().equals(Property.MaintainUpkeepType.TYPE_2.getCode())){
				fileKey = FileType.TypeEnum.FILE_TYPE_1002.getCode()+"-"+i.getId();
			}else if(i.getType().equals(Property.MaintainUpkeepType.TYPE_3.getCode())){
				fileKey = FileType.TypeEnum.FILE_TYPE_1003.getCode()+"-"+i.getId();
			}
			if(fileMap.containsKey(fileKey)){
				i.setFiles(fileMap.get(fileKey));
			}else{
				i.setFiles(new ArrayList<>());
			}

			//用户
			i.setNickName(sysUserService.getNameByMap(userMap,i.getUserId()));

			//资产分类
			if(i.getPropertyTypeId().equals(PropertyType.IdEnum.ID_4.getCode())&&propertyTypeMap.containsKey(i.getPropertyTypeId3())){
				i.setPropertyTypeName3(propertyTypeService.getNameByMap(propertyTypeMap,i.getPropertyTypeId3()));
			}
		}

		return list;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void jiankePushData(JiankePushDataDTO dto){
		//签名验证
		//建科提供的签名 lz//V33AT7tnluSmrtfEoRvnhTcG5vIct2YIc4rblxW3vIlK0rBGb1QYkp5Nykk5ePF3unOas+z/lUhWHQM0/MmsnXLm6KDpYzd5IP5aEVotRPn+8SbKKygKP3mp8yfUPDvzKXtENut0uc7qCXPl42lHHbfUkXlMpcnwjHB1hxM=
		boolean verify = SecurityUtils.verify(UserContext.getUser().getJianKeToken(), dto.getSignature(), jianKeProperties.getPublicKey());
		if(!verify){
			throw new ServiceException(ErrorCode.ERROR_11000.getCode(),ErrorCode.ERROR_11000.getDescribe());
		}

		//验证是否有这个资产
		LambdaQueryWrapper<Property> lqw = new LambdaQueryWrapper<>();
		lqw.eq(Property::getTripartitePropertyId,dto.getPropertyUniqueCode());
		Property property = this.getOne(lqw);
		if(Objects.isNull(property)){
			throw new ServiceException(ErrorCode.ERROR_12000.getCode(),ErrorCode.ERROR_12000.getDescribe());
		}

		Integer type = dto.getType();
		if(PropertyRunData.JiankeRequestTypeEnum.TYPE_1.getCode().equals(type)){
			PropertyRunData.lineState data;
			try {
				//验证data中的json字符串能否转换bean成功
				data = JSONUtil.toBean(dto.getData(), PropertyRunData.lineState.class);
			} catch (Exception e) {
				e.printStackTrace();
				throw new ServiceException(ErrorCode.ERROR_13000.getCode(),ErrorCode.ERROR_13000.getDescribe());
			}
			//是否在线的业务处理
			lineState(dto.getPropertyUniqueCode(),data);

		}else if(PropertyRunData.JiankeRequestTypeEnum.TYPE_2.getCode().equals(type)){
			PropertyRunData.AlarmState data;
			try {
				//验证data中的json字符串能否转换bean成功
				data = JSONUtil.toBean(dto.getData(), PropertyRunData.AlarmState.class);
			} catch (Exception e) {
				e.printStackTrace();
				throw new ServiceException(ErrorCode.ERROR_13000.getCode(),ErrorCode.ERROR_13000.getDescribe());
			}
			//是否告警的业务处理
			alarmState(dto.getPropertyUniqueCode(),data);

		}else if(PropertyRunData.JiankeRequestTypeEnum.TYPE_3.getCode().equals(type)){
			try {
				//验证data中的json字符串能否转换bean成功
				PropertyRunData.DeviceAttribute deviceReads = JSONUtil.toBean(dto.getData(), PropertyRunData.DeviceAttribute.class);
				log.info(JSONUtil.toJsonStr(deviceReads));
			} catch (Exception e) {
				e.printStackTrace();
				throw new ServiceException(ErrorCode.ERROR_13000.getCode(),ErrorCode.ERROR_13000.getDescribe());
			}

		}else if(PropertyRunData.JiankeRequestTypeEnum.TYPE_4.getCode().equals(type)){
			try {
				//验证data中的json字符串能否转换bean成功
				PropertyRunData.DeviceOperation deviceReads = JSONUtil.toBean(dto.getData(), PropertyRunData.DeviceOperation.class);
				log.info(JSONUtil.toJsonStr(deviceReads));
			} catch (Exception e) {
				e.printStackTrace();
				throw new ServiceException(ErrorCode.ERROR_13000.getCode(),ErrorCode.ERROR_13000.getDescribe());
			}
		}

		//修改以前的数据为历史数据
		//准备需要修改的数据
		PropertyRunData propertyRunDataUpd = new PropertyRunData();
		propertyRunDataUpd.setIsNew(Constants.NO);
		//修改条件
		LambdaUpdateWrapper<PropertyRunData> luw = new LambdaUpdateWrapper<>();
		luw.eq(PropertyRunData::getPropertyUniqueCode, dto.getPropertyUniqueCode());
		luw.eq(PropertyRunData::getType, dto.getType());
		luw.eq(PropertyRunData::getIsNew, Constants.YES);
		luw.eq(PropertyRunData::getDeleteFlag, Constants.NO);
		//开始修改
		propertyRunDataService.update(propertyRunDataUpd, luw);

		//保存本次请求的数据
		PropertyRunData propertyRunData = BeanUtil.copyProperties(dto, PropertyRunData.class);
		propertyRunData.setJsonData(dto.getData());
		propertyRunDataService.save(propertyRunData);

		//发送消息
		if(PropertyRunData.JiankeRequestTypeEnum.TYPE_3.getCode().equals(type)){
			return;
		}
		//发送消息 是否在线+告警
		MessageInfo messageInfo = new MessageInfo();
		property = this.getOne(lqw);
		if(PropertyRunData.JiankeRequestTypeEnum.TYPE_1.getCode().equals(type)||PropertyRunData.JiankeRequestTypeEnum.TYPE_2.getCode().equals(type)){
			//准备消息体
			MessageAlarmContent MessageAlarmContent = new MessageAlarmContent();
			MessageAlarmContent.setUeCode(property.getUeCode());
			MessageAlarmContent.setState(Property.PropertyUeStateEnum.convertState(property.getIsOffline(), property.getAlarmState()));

			messageInfo.setEvent(MessageInfo.EventEnum.device_state.getCode());
			messageInfo.setContent(MessageAlarmContent);
		}else

		//发送消息 设备操作数据 目前表示了灯开关、窗帘开合的数据
		if(PropertyRunData.JiankeRequestTypeEnum.TYPE_4.getCode().equals(type)){

			PropertyRunData.DeviceOperation deviceOperation = JSONUtil.toBean(dto.getData(), PropertyRunData.DeviceOperation.class);
			List<PropertyRunData.DeviceReadsItem> operationData = deviceOperation.getOperationData();
			if(CollUtil.isEmpty(operationData)){
				throw new ServiceException(ErrorCode.ERROR_14000.getCode(),ErrorCode.ERROR_14000.getDescribe());
			}
			PropertyRunData.DeviceReadsItem deviceReadsItem = operationData.get(0);
			if(Objects.isNull(deviceReadsItem)){
				throw new ServiceException(ErrorCode.ERROR_14000.getCode(),ErrorCode.ERROR_14000.getDescribe());
			}
			if(Objects.isNull(deviceReadsItem.getValue())){
				throw new ServiceException(ErrorCode.ERROR_14000.getCode(),ErrorCode.ERROR_14000.getDescribe());
			}

			if(deviceOperation.getDeviceDataType().equals(PropertyRunData.DeviceDataTypeEnum.TYPE_1.getCode())){
				//switch_on 0关 1开
				if(!"switch_on".equals(deviceReadsItem.getKey())){
					throw new ServiceException(ErrorCode.ERROR_13001.getCode(),ErrorCode.ERROR_13001.getDescribe());
				}

				MessageLampSwitch mls = new MessageLampSwitch();
				mls.setUeCode(dto.getPropertyUniqueCode());
				mls.setSwitchOn(deviceReadsItem.getValue());

				messageInfo.setEvent(MessageInfo.EventEnum.lamp_switch.getCode());
				messageInfo.setContent(JSONUtil.toJsonStr(mls));
			}else{
				//窗帘的开合 开合度 0 - 100， 0 表示全关，100 表示全开
				if(!"opener_current".equals(deviceReadsItem.getKey())){
					throw new ServiceException(ErrorCode.ERROR_13002.getCode(),ErrorCode.ERROR_13002.getDescribe());
				}

				MessageCurtainSwitch mcs = new MessageCurtainSwitch();
				mcs.setUeCode(dto.getPropertyUniqueCode());
				mcs.setOpenerCurrent(deviceReadsItem.getValue());

				messageInfo.setEvent(MessageInfo.EventEnum.curtain_switch.getCode());
				messageInfo.setContent(JSONUtil.toJsonStr(mcs));
			}
		}
		//发送消息
		WebSocketJiankeSever.sendAllMessage(JSONUtil.toJsonStr(messageInfo));
	}

	public void lineState(String propertyUniqueCode,PropertyRunData.lineState data){
		//准备需要修改的数据
		Property propertyUpd = new Property();
		propertyUpd.setIsOffline(data.getState());
		//修改条件
		LambdaUpdateWrapper<Property> luw = new LambdaUpdateWrapper<>();
		luw.eq(Property::getTripartitePropertyId, propertyUniqueCode);
		//开始修改
		this.update(propertyUpd, luw);
	}

	public void alarmState(String propertyUniqueCode,PropertyRunData.AlarmState data){
		//准备需要修改的数据
		Property propertyUpd = new Property();
		propertyUpd.setIsOffline(data.getState());
		//修改条件
		LambdaUpdateWrapper<Property> luw = new LambdaUpdateWrapper<>();
		luw.eq(Property::getTripartitePropertyId, propertyUniqueCode);
		//开始修改
		this.update(propertyUpd, luw);
	}

	@Override
	public List<PropertyUeVO> getUeList(){
		LambdaQueryWrapper<Property> lqw = new LambdaQueryWrapper<>();
		lqw.eq(Property::getDeleteFlag,Constants.NO);
		lqw.eq(Property::getIsIdle,Constants.NO);
		lqw.isNotNull(Property::getUeCode).ne(Property::getUeCode,"");
		List<Property> list = this.list(lqw);
		if(CollUtil.isEmpty(list)){
			return new ArrayList<>();
		}
		List<PropertyUeVO> result = BeanUtil.copyToList(list, PropertyUeVO.class);

		LocalDateTime currentDate = LocalDateTime.now();
		for(PropertyUeVO i:result){
			//状态state
			i.setState(Property.PropertyUeStateEnum.convertState(i.getIsOffline(),i.getAlarmState()));

			//保养状态
			//构件的资产 单个资产不应该设置保养数据 因为构件是按照分类保养的 数据库中资产有保养数据 是因为建科的视图需要 所以在改分类保养数据的时候 会同步给这个分类下面的子类资产
			if(!PropertyType.IdEnum.ID_4.getCode().equals(i.getPropertyTypeId())){
				i.setMaintainState(Property.MaintainStateEnum.convertState(i.getIsMaintain(),i.getNextTimeMaintain(),currentDate));
			}

			//更换状态
			i.setChangeState(Property.ChangeStateEnum.convertState(i.getIsChange(),i.getLatelyChangeDate(),currentDate));

			//设置propertyTypeIdLeaf
			//资产所属资产分类叶子节点id 目前来说 如果是构件就是资产三级分类id 如果是非构件 就是资产二级分类id
			if(PropertyType.IdEnum.ID_4.getCode().equals(i.getPropertyTypeId())){
				i.setPropertyTypeIdLeaf(i.getPropertyTypeId3());
			}else{
				i.setPropertyTypeIdLeaf(i.getPropertyTypeId2());
			}
		}
		return result;
	}

	/**
	 * 保养+更换每天1点和12点30执行状态检查
	 */
	@Scheduled(cron = "0 0 1 * * ?")
	@Override
	public void maintainChangeState() {
		MessageInfo messageInfo = new MessageInfo(MessageInfo.EventEnum.maintain_change_state_refresh.getCode(),"");
		//发送消息
		WebSocketJiankeSever.sendAllMessage(JSONUtil.toJsonStr(messageInfo));
	}
	@Scheduled(cron = "0 30 12 * * ?")
	public void maintainChangeState2() {
		MessageInfo messageInfo = new MessageInfo(MessageInfo.EventEnum.maintain_change_state_refresh.getCode(),"");
		//发送消息
		WebSocketJiankeSever.sendAllMessage(JSONUtil.toJsonStr(messageInfo));
	}

	@Override
	@SneakyThrows
	@Transactional(rollbackFor = Exception.class)
	public void importZhuJian(MultipartFile file) {

		//获取excel里面的数据
		List<PropertyImportDTO> list = new ArrayStack();
		//监听器
		AnalysisEventListener<PropertyImportDTO> listener = new AnalysisEventListener<PropertyImportDTO>() {
			@Override
			public void invoke(PropertyImportDTO data, AnalysisContext analysisContext){
				list.add(data);
			}
			//读取结束的监听
			@Override
			public void doAfterAllAnalysed(AnalysisContext analysisContext) {
			}
		};

        /*
        headRowNumber 表头在哪一行 从1开始计算
        sheet sheet下标 从0开始
         */
		EasyExcel.read(file.getInputStream(), PropertyImportDTO.class, listener).headRowNumber(3).sheet(0).doRead();
		if (CollectionUtils.isEmpty(list)) {
			throw new ServiceException("excel中没有数据");
		}

		//查询以前资产的map数据 key为tripartitePropertyId
		List<Property> propertys = this.list();
		Map<String,Property> map = propertys.stream()
				.collect(Collectors.toMap(i -> i.getTripartitePropertyId(), Function.identity()));

		Map<String,String> verification = new HashMap<>();
		Set<String> tripartitePropertyIdSet = new HashSet<>();
		for(PropertyImportDTO i:list){

			if(StrUtil.isBlank(i.getComponentUniqueCode())||StrUtil.isBlank(i.getComponentName())){
				throw new ServiceException("构件唯一编码、构件名称都不能为空");
			}

			if(!i.getIsSmart().equals("是")&&!i.getIsSmart().equals("否")){
				verification.put(i.getComponentUniqueCode()+"   "+i.getComponentName(),"是否是智能设备 只能填写是或否");
				continue;
			}

			if(tripartitePropertyIdSet.contains(i.getComponentUniqueCode())){
				verification.put(i.getComponentUniqueCode()+"   "+i.getComponentName(),"存在重复");
			}
			tripartitePropertyIdSet.add(i.getComponentUniqueCode());
		}

		if (MapUtil.isNotEmpty(verification)) {
			System.out.println(verification);
			throw new ServiceException("数据检查异常");
		}

		List<Property> propertyAdds = new ArrayList<>();
		List<Property> propertyUpds = new ArrayList<>();
		//UE信息
		List<PropertyBimUeInfo> propertyBimUeInfos = new ArrayList<>();
		for(PropertyImportDTO i:list){
			if(!map.containsKey(i.getComponentUniqueCode())){
				//新增
				Property property = new Property();
				property.setTripartitePropertyId(i.getComponentUniqueCode());
				property.setPropertyCode(systemCommonService.getUniqueNum(SystemCommon.UniqueNumEnum.PROPERTY_SN.getPrefix(), SystemCommon.UniqueNumEnum.PROPERTY_SN.getRedisKey()));
				property.setName(i.getComponentName());
				property.setIsSmart(i.getIsSmart().equals("是")?1:0);
				property.setMaintainPeriod(StrUtil.isNotBlank(i.getMaintainPeriod())?Integer.parseInt(i.getMaintainPeriod()):0);
				property.setBelongingArea(i.getBelongingArea());
				property.setBrand(i.getBrand());
				propertyAdds.add(property);
			}else{
				//更新
				Property propertyUpd = new Property();
				propertyUpd.setId(map.get(i.getComponentUniqueCode()).getId());
				propertyUpd.setName(i.getComponentName());
				propertyUpd.setIsSmart(i.getIsSmart().equals("是")?1:0);
				propertyUpd.setMaintainPeriod(StrUtil.isNotBlank(i.getMaintainPeriod())?Integer.parseInt(i.getMaintainPeriod()):0);
				propertyUpd.setUpdateTime(LocalDateTime.now());
				propertyUpd.setBelongingArea(i.getBelongingArea());
				propertyUpd.setBrand(i.getBrand());
				propertyUpds.add(propertyUpd);
			}

			PropertyBimUeInfo pbi = new PropertyBimUeInfo();
			pbi.setBimCode(i.getComponentUniqueCode());
			pbi.setUeCode(i.getComponentUniqueCode());
			propertyBimUeInfos.add(pbi);
		}

		//不存在就插入
		if(CollUtil.isNotEmpty(propertyAdds)){
			this.saveBatch(propertyAdds);
		}

		//存在就更新
		if(CollUtil.isNotEmpty(propertyUpds)){
			this.updateBatchById(propertyUpds);
		}

		//UE信息表清空在插入
		propertyBimUeInfoMapper.truncateTable();
		if(CollUtil.isNotEmpty(propertyBimUeInfos)){
			propertyBimUeInfoService.saveBatch(propertyBimUeInfos);
		}

	}

	@Override
	@SneakyThrows
	@Transactional(rollbackFor = Exception.class)
	public void importBim(MultipartFile file) {
		//获取excel里面的数据
		List<PropertyBimImportDTO> list = new ArrayStack();
		//监听器
		AnalysisEventListener<PropertyBimImportDTO> listener = new AnalysisEventListener<PropertyBimImportDTO>() {
			@Override
			public void invoke(PropertyBimImportDTO data, AnalysisContext analysisContext){
				list.add(data);
			}
			//读取结束的监听
			@Override
			public void doAfterAllAnalysed(AnalysisContext analysisContext) {
			}
		};

        /*
        headRowNumber 表头在哪一行 从1开始计算
        sheet sheet下标 从0开始
         */
		EasyExcel.read(file.getInputStream(), PropertyBimImportDTO.class, listener).headRowNumber(2).sheet(0).doRead();
		if (CollectionUtils.isEmpty(list)) {
			throw new ServiceException("excel中没有数据");
		}

		List<PropertyType> propertyTypes = propertyTypeService.list();
		Map<String, String> propertyTypeMap = propertyTypes.stream()
				.collect(Collectors.toMap(
						i -> i.getParentNamesImport(),
						i -> i.getParentIdsImport()));

		List<Property> propertys = this.list();
		Map<String, Integer> propertyMap = propertys.stream()
				.collect(Collectors.toMap(
						i -> i.getTripartitePropertyId(),
						i -> i.getId()));



		Map<String,String> verification = new HashMap<>();
		for(PropertyBimImportDTO i:list){
			if(StrUtil.isBlank(i.getSerialNumber())){
				throw new ServiceException("序号一定不能为空");
			}

			if(StrUtil.isBlank(i.getPropertyId())&&StrUtil.isBlank(i.getPropertyId2())){
				verification.put(i.getSerialNumber(),"property_id和property_id2 不能同时为空");
				continue;
			}

			if(StrUtil.isBlank(i.getPropertyType())||StrUtil.isBlank(i.getPropertyType2())){
				verification.put(i.getSerialNumber(),"property_type和property_type2 两个都不能为空");
				continue;
			}

			if(StrUtil.isBlank(i.getName())&&StrUtil.isBlank(i.getNameNew())){
				verification.put(i.getSerialNumber(),"name、nameNew 不能同时为空");
				continue;
			}

			if (i.getPropertyType().equals("构件")&&StrUtil.isBlank(i.getPropertyType3())) {
				verification.put(i.getSerialNumber(),"如果是构件 property_type3不能为空");
				continue;
			}

			String parentNamesImport = i.getPropertyType()+","+i.getPropertyType2();
			if (!StrUtil.isEmpty(i.getPropertyType3())) {
				parentNamesImport = parentNamesImport+","+i.getPropertyType3();
			}
			if(!propertyTypeMap.containsKey(parentNamesImport)){
				verification.put(i.getSerialNumber(),"资产类型和数据库类型匹配不上");
				continue;
			}

			if(StrUtil.isNotBlank(i.getPropertyId())&&!propertyMap.containsKey(i.getPropertyId())){
				verification.put(i.getSerialNumber(),"智能资产在数据库中匹配不上");
				continue;
			}
		}
		if (MapUtil.isNotEmpty(verification)) {
			System.out.println(verification);
			throw new ServiceException("数据检查异常");
		}

		Set<String> ueCodeSet = propertyBimUeInfoService.list().stream().map(i -> i.getUeCode()).collect(Collectors.toSet());

		//智能资产编辑
		List<Property> propertyUpds = new ArrayList<>();
		//非智能资产新增
		List<Property> propertyNotSmartAdds = new ArrayList<>();
		//非智能资产编辑
		List<Property> propertyNotSmartUpds = new ArrayList<>();
		//UE信息新增
		List<PropertyBimUeInfo> propertyBimUeInfoAdds = new ArrayList<>();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		for(PropertyBimImportDTO i:list){
			//组装类型名称集
			String parentNamesImport = i.getPropertyType()+","+i.getPropertyType2();
			if (!StrUtil.isEmpty(i.getPropertyType3())) {
				parentNamesImport = parentNamesImport+","+i.getPropertyType3();
			}
			//通过名称集获取类型id集
			String parentIds = propertyTypeMap.get(parentNamesImport);
			String[] split = parentIds.split(",");

			//获取三方资产唯一id
			String propertyId = i.getPropertyId();
			if(StrUtil.isBlank(i.getPropertyId())){//如果propertyId有值 表示是智能资产 如果没有值 表示是非智能资产
				propertyId = i.getPropertyId2();
			}

			//获取资产名称
			String name = "";
			if(StrUtil.isNotBlank(i.getName())){
				name = i.getName();
			}
			//if(StrUtil.isNotBlank(i.getNameNew())){
			//	name = i.getNameNew();
			//}

			//创建资产对象
			Property p = new Property();

			//资产类型
			p.setPropertyTypeId(Integer.parseInt(split[0]));
			p.setPropertyTypeId2(Integer.parseInt(split[1]));
			if(split.length==3){
				p.setPropertyTypeId3(Integer.parseInt(split[2]));
			}

			//归属区域 例如卫生间、客厅、  厨房等belonging_area
			p.setBelongingArea(i.getBelongingArea());

			//更换日期
			if(StrUtil.isNotBlank(i.getLatelyChangeDate())){
				String latelyChangeDate = i.getLatelyChangeDate();
				latelyChangeDate = latelyChangeDate+" 00:00:00";
				LocalDateTime localDateTime = LocalDateTime.parse(latelyChangeDate, formatter);

				p.setIsChange(Constants.YES);
				p.setLatelyChangeDate(localDateTime);
			}

			//安装日期
			if(StrUtil.isNotBlank(i.getInstallDate())){
				String installDate = i.getInstallDate();
				installDate = installDate+" 00:00:00";
				LocalDateTime localDateTime = LocalDateTime.parse(installDate, formatter);

				p.setInstallDate(localDateTime);
			}

			//保养周期（单位：月）
			if(StrUtil.isNotBlank(i.getMaintainPeriod())){
				p.setMaintainPeriod(Integer.parseInt(i.getMaintainPeriod()));
			}

			//保养日期
			if(StrUtil.isNotBlank(i.getNextTimeMaintain())){
				String nextTimeMaintain = i.getNextTimeMaintain();
				nextTimeMaintain = nextTimeMaintain+" 00:00:00";
				LocalDateTime localDateTime = LocalDateTime.parse(nextTimeMaintain, formatter);

				p.setIsMaintain(Constants.YES);
				p.setNextTimeMaintain(localDateTime);
			}

			//质保期
			p.setWarranty(i.getWarranty());

			//使用年限
			p.setDurableYears(i.getDurableYears());

			//此资产在三维模型中是否可以点击 0否 1是 默认0
			p.setIsClickModel(i.getIsClickModel());

			//智能资产进行修改
			if(StrUtil.isNotBlank(i.getPropertyId())){//如果propertyId有值 表示是智能资产 如果没有值 表示是非智能资产
				p.setId(propertyMap.get(propertyId));
				//p.setName(name);//智能资产使用的名字是住建运营提供的文档 所以这里注释掉
				p.setBrand(i.getBrand());
				p.setBimCode(propertyId);
				p.setUeCode(propertyId);
				propertyUpds.add(p);

			}else{
				//非智能资产根据情况进行新增修改
				p.setName(name);
				p.setBrand(i.getBrand());
				p.setBimCode(propertyId);
				p.setUeCode(propertyId);

				if(propertyMap.containsKey(propertyId)){//包含 修改
					p.setId(propertyMap.get(propertyId));
					propertyNotSmartUpds.add(p);
				}else{
					//不包含 新增
					p.setPropertyCode(systemCommonService.getUniqueNum(SystemCommon.UniqueNumEnum.PROPERTY_SN.getPrefix(), SystemCommon.UniqueNumEnum.PROPERTY_SN.getRedisKey()));
					p.setTripartitePropertyId(i.getPropertyId2());
					p.setIsSmart(Constants.NO);
					propertyNotSmartAdds.add(p);
				}
			}

			//UE信息
			if(!ueCodeSet.contains(propertyId)){
				PropertyBimUeInfo pbi = new PropertyBimUeInfo();
				pbi.setBimCode(propertyId);
				pbi.setUeCode(propertyId);
				propertyBimUeInfoAdds.add(pbi);
			}
		}

		if(CollUtil.isNotEmpty(propertyUpds)){
			this.updateBatchById(propertyUpds);
		}
		if(CollUtil.isNotEmpty(propertyNotSmartAdds)){
			this.saveBatch(propertyNotSmartAdds);
		}
		if(CollUtil.isNotEmpty(propertyNotSmartUpds)){
			this.updateBatchById(propertyNotSmartUpds);
		}

		if(CollUtil.isNotEmpty(propertyBimUeInfoAdds)){
			propertyBimUeInfoService.saveBatch(propertyBimUeInfoAdds);
		}
	}


	@Resource(name = "wsslExecutor")
	private ExecutorService wsslExecutor;

	@Override
	@SneakyThrows
	@Transactional(rollbackFor = Exception.class)
	public void importFile(MultipartFile file) {

		//excel数据读取
		List<PropertyBimImportDTO> propertyBimImportDTOs = new ArrayStack();
		//监听器
		AnalysisEventListener<PropertyBimImportDTO> listener = new AnalysisEventListener<PropertyBimImportDTO>() {
			@Override
			public void invoke(PropertyBimImportDTO data, AnalysisContext analysisContext){
				propertyBimImportDTOs.add(data);
			}
			//读取结束的监听
			@Override
			public void doAfterAllAnalysed(AnalysisContext analysisContext) {
			}
		};

        /*
        headRowNumber 表头在哪一行 从1开始计算
        sheet sheet下标 从0开始
         */
		EasyExcel.read(file.getInputStream(), PropertyBimImportDTO.class, listener).headRowNumber(2).sheet(0).doRead();
		if (CollectionUtils.isEmpty(propertyBimImportDTOs)) {
			throw new ServiceException("excel中没有数据");
		}

		//资产图片读取
		String directoryPath = "C:\\Users\\weishishulian\\Desktop\\养老现场资产设备照片\\";
		List<File> files = new ArrayList<>();
		//递归遍历目录并处理目录下的文件（子目录也会遍历），可以处理目录或文件
		FileUtil.walkFiles(new File(directoryPath), new Consumer<File>() {
			@Override
			public void accept(File file) {
				files.add(file);
			}
		});
		System.out.println(JSONUtil.toJsonStr(files));
		//for(File i:files){
		//	System.out.println(i.getName());
		//}
		Map<String,File> fileMap = files.stream()
				.collect(Collectors.toMap(i -> i.getName(), Function.identity()));

		//查询以前资产的map数据 key为tripartitePropertyId
		List<Property> propertys = this.list();
		Map<String,Property> propertyMap = propertys.stream()
				.collect(Collectors.toMap(i -> i.getTripartitePropertyId(), Function.identity()));

		// 创建 CompletableFuture 列表
		List<CompletableFuture<Void>> futures = new ArrayList<>();
		// 标记任务是否有错误
		AtomicBoolean executorFlag = new AtomicBoolean(false);
		Map<String,String>  executeFailMap = new HashMap<>();
		for (PropertyBimImportDTO i : propertyBimImportDTOs) {
			// 提交任务到线程池
			CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
				// 模拟任务逻辑
				//System.out.println(Thread.currentThread().getName() + " 执行任务: " + i.getSerialNumber());
				try {
					//Thread.sleep(1); // 模拟任务耗时
					propertyFileHandle(i,propertyMap,fileMap);
				} catch (Exception e) {
					executorFlag.set(true);
					executeFailMap.put(i.getSerialNumber(),"处理失败 图片名："+i.getImageNum()+".png");
					e.printStackTrace();
				}
			}, wsslExecutor);

			futures.add(future);
		}

		// 等待所有任务完成
		CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
		System.out.println("所有任务执行完成！");
		// 关闭线程池 这是公共的线程池 所有不能关闭
		//wsslExecutor.shutdown();

		// 根据标记判断是否有任务失败
		//if (executorFlag.get()) {
		//	throw new ServiceException("任务执行中发生错误");
		//}

		System.out.println("执行过程错误打印：");
		System.out.println(executeFailMap);
	}

	public void propertyFileHandle(
			PropertyBimImportDTO propertyBimImportDTO,
			Map<String,Property> propertyMap,
			Map<String,File> fileMap
	){
		if(StrUtil.isBlank(propertyBimImportDTO.getImageNum())){
			return;
		}
		propertyBimImportDTO.setImageNum(propertyBimImportDTO.getImageNum()+".png");

		String tripartitePropertyId = "";
		if(StrUtil.isNotBlank(propertyBimImportDTO.getPropertyId())){//如果propertyId有值 表示是智能资产 如果没有值 表示是非智能资产
			tripartitePropertyId = propertyBimImportDTO.getPropertyId();
		}else{
			tripartitePropertyId = propertyBimImportDTO.getPropertyId2();
		}

		Property property = propertyMap.get(tripartitePropertyId);

		//表示没有文件 直接上传
		if(StrUtil.isBlank(property.getImageNum())){
			File2VO file2VO = fileService.upload(FileType.TypeEnum.FILE_TYPE_1000.getCode(), fileMap.get(propertyBimImportDTO.getImageNum()));
			fileService.addSave(property.getId(),Lists.newArrayList(file2VO.getId()));

			Property property2 = new Property();
			property2.setId(property.getId());
			property2.setImageNum(propertyBimImportDTO.getImageNum());
			this.updateById(property2);

			return;
		}

		//表示有文件 但是没有进行修改 直接返回 不进行处理
		if(property.getImageNum().equals(propertyBimImportDTO.getImageNum())){
			return;
		}

		//表示有文件 但是进行了修改
		File2VO file2VO = fileService.upload(FileType.TypeEnum.FILE_TYPE_1000.getCode(), fileMap.get(propertyBimImportDTO.getImageNum()));
		fileService.updSave(FileType.TypeEnum.FILE_TYPE_1000.getCode(),property.getId(),Lists.newArrayList(file2VO.getId()));

		Property property2 = new Property();
		property2.setId(property.getId());
		property2.setImageNum(propertyBimImportDTO.getImageNum());
		this.updateById(property2);
		return;
	}

}



